package iceberg.readers;

import iceberg.constraints.ConstraintException;
import iceberg.domain.Layer;
import iceberg.domain.StructureDefinition;
import iceberg.domain.Unit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;

class StructureDefinitionReader extends AbstractReader{

	private static final Logger LOG = LoggerFactory.getLogger(StructureDefinitionReader.class);

	private Map<String, Layer> layers;
	private final StructureDefinition definition = new StructureDefinition();
	private Map<String, ConstraintException> exceptions;

	public void setLayers(Map<String, Layer> layers) {
		this.layers = layers;
	}

	public void setExceptions(Map<String, ConstraintException> exceptions) {
		this.exceptions = exceptions;
	}

	public StructureDefinition read() throws ParserConfigurationException, IOException, SAXException {
		Element root = getXMLRootOfFile("SD.xml");

		NodeList nodeList = root.getElementsByTagName("layer");
		for (int i = 0; i < nodeList.getLength(); i++) {
			Element layerElement = (Element) nodeList.item(i);
			String layerName = layerElement.getAttribute("name");

			Layer layer = layers.get(layerName);
			if (layer == null) {
				LOG.error("Unable to find layer '{}'", layerName);
			} else {
				NodeList packageElements = layerElement.getElementsByTagName("package");
				for (int j = 0; j < packageElements.getLength(); j++) {
					String name = ((Element) packageElements.item(j)).getAttribute("name");

					Unit unit = Unit.createPackageUnit(name);
					layer.addUnit(unit);
				}
			}
		}

		buildExceptions(root);

		definition.setLayers(new HashSet<Layer>(layers.values()));

		return definition;
	}

	private void buildExceptions(Element root) {
		NodeList nodeList = root.getElementsByTagName("exception");
		for (int i = 0; i < nodeList.getLength(); i++) {
			Element element = (Element) nodeList.item(i);
			String name = element.getAttribute("name");
			String className = element.getAttribute("class");

			ConstraintException exception = exceptions.get(name);
			if (exception != null) {
				exception.setClassName(className);
				definition.addConstraintException(className, exception);
			}
		}

	}
}
